<?php
namespace DRY\Module;

/**
 * DonReY Framework 2012 :: Database access module, this is the lowest level module for database access, it represents the DB connection
 * @method result query() Run a SQL query
 *
 * @author Wavetrex <wavetrex@gmail.com>
 * @link http://www.donrey.net/Documentation/Structure/Modules/database.html
 * @license [GPL v3] http://www.gnu.org/licenses/gpl-3.0.html
 * @version 1.0.dev
 * @package DonReY
 * @subpackage Module.Database
 */
class Database extends base
{
	const
		EXC_NOT_CONNECTED_ON_QUERY = 1;

	const
		Autoload_Directory = 'database',
		Autoload_Prefix = 'DRY\Database\Driver',
		Autoload_Suffix = 'driver'
		;

	/**
	 * Autoconfiguration method, creates the required elements in the config, to use a database
	 *
	 * @param SimpleXMLElement $CFG
	 * @param array $input
	 */
	public static function setup_Config(\SimpleXMLElement &$CFG, $input = null)
	{
		// engine to use (defaults to mysqli)
		$driver = $CFG-> addChild('driver', isset($input['driver'])?$input['driver']:"mysqli");
		if(isset($input['connect']))
			$driver['connect'] = $input['connect'];
		if(isset($input['debug']))
			$driver['debug'] = $input['debug'];

		// engine parameters
		$CFG-> addChild('server', isset($input['server'])?$input['server']:"localhost");
		$CFG-> addChild('username', isset($input['username'])?$input['username']:"root");
		$CFG-> addChild('password', isset($input['password'])?$input['password']:"");
		$CFG-> addChild('dbname', isset($input['dbname'])?$input['dbname']:"");
	}

	/**
	 * Autoconfiguration method, similar to setup_Config however this copies and changes an existing configuration into a new one.
	 *
	 * @param SimpleXMLElement $CFG
	 * @param array $input
	 */
	public static function update_Config(SimpleXMLElement $original_CFG, $input = null)
	{
		$CFG = clone($original_CFG);

		if(!empty($input['connect']))
			$CFG-> driver-> connect = $input['connect'];
		if(!empty($input['debug']))
			$CFG-> driver-> debug = $input['debug'];

		if(!empty($input['server']))
			$CFG-> server = $input['server'];
		if(!empty($input['username']))
			$CFG-> username = $input['username'];
		if(!empty($input['password']))
			$CFG-> password = $input['password'];
		if(!empty($input['dbname']))
			$CFG-> dbname = $input['dbname'];

		return $CFG;
	}

	public function control_Command($command)
	{
		switch($command) {
			case 'ExportConfig':
				$exp = array('module'=> array('alias'=> $this->_alias));
				$exp['connection'] = array(
					'driver'=> (string)$this-> CFG-> driver,
					'server'=> (string)$this-> CFG-> server,
					'username'=> (string)$this-> CFG-> username,
//					'password'=> (string)$this-> CFG-> password, // The password is not exported intentionally.
					'database'=> (string)$this-> CFG-> dbname
				);
				return $exp;

			case 'TestConnection':
				// lazy connection
				if(!$this-> connection)
					$this-> connect();
				return $this-> connection-> is_Connected();
		}
	}

	/**
	 * The connection object
	 * @var \DRY\Database\Driver_base
	 */
	private $connection;

	/**
	 * Module Constructor - Starts the connection if driver config tells it to
	 * @param string $alias
	 * @param \SimpleXMLElement $config
	 */
	public function __construct($alias, $config)
	{
		parent::__construct($alias, $config);

		// ... but do not necessarily instance it
		if(!(isset($config-> driver['connect']) && $config-> driver['connect'] == 'lazy'))
			$this-> connect();
	}

	/**
	 * Creates the connection object
	 */
	private function connect()
	{
		$db_class = self::Autoload_Prefix.'_'.($this-> CFG-> driver?:'mysqli'); // defaults to MySQLi since it's the most used
		$this-> connection = new $db_class($this-> CFG, $this);
	}

	/**
	 * Function pass-through to database driver
	 *
	 * @param string $fname
	 * @param array $args
	 * @return mixed return from the database driver
	 */
	public function __call($fname,$args)
	{
		// lazy connection
		if(!$this-> connection)
			$this-> connect();

		// TODO: A way to check if the function actually exists
		if($this-> connection-> is_Connected())
			return call_user_func_array(array($this-> connection,$fname),$args);
	}

	/**
	 * Variable pass-through to database driver
	 *
	 * @param string $name
	 */
	public function __get($name)
	{
		// lazy connection
		if(!$this-> connection)
			$this-> connect();

		return $this-> connection-> $name;
	}

}

namespace DRY\Database;

/**
 * Database driver required functions
 *
 * @author Wavetrex <wavetrex@gmail.com>
 * @link http://www.donrey.net/Documentation/Structure/Modules/database.html
 * @license [GPL v3] http://www.gnu.org/licenses/gpl-3.0.html
 * @version 1.0.dev
 * @package DonReY
 * @subpackage Module.Database
 */
interface Driver_base
{
	/**
	 * Runs a query string directly and returns the result
	 * @param string $query
	 */
	public function query($query);
}

/**
 * Database driver - Query result required functions
 *
 * @author Wavetrex <wavetrex@gmail.com>
 * @link http://www.donrey.net/Documentation/Structure/Modules/database.html
 * @license [GPL v3] http://www.gnu.org/licenses/gpl-3.0.html
 * @version 1.0.dev
 * @package DonReY
 * @subpackage Module.Database
 */
interface Driver_result_base
{

}